#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
基于简历的RAG岗位推荐API

功能：
1. 接收前端上传的简历文件（PDF/Word/TXT）
2. 解析简历内容并提取关键信息
3. 通过RAG流程检索匹配岗位（ES稀疏检索 + Milvus稠密检索）
4. 使用LLM生成推荐理由
5. 返回推荐岗位列表和匹配分析

作者：AI助手
日期：2024
"""

import os
import json
import tempfile
from typing import Dict, Any
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from django.utils.decorators import method_decorator
from django.views import View
import logging

# 设置日志
logger = logging.getLogger(__name__)

# 导入简历解析功能
import sys
import os

# 添加项目根目录到Python路径
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if project_root not in sys.path:
    sys.path.append(project_root)

try:
    from resume_hybrid_search_system import (
        parse_resume_content,
        extract_key_info_from_resume,
        process_resume_and_recommend_jobs,
        Config
    )
    RAG_SYSTEM_AVAILABLE = True
except ImportError as e:
    print(f"⚠️ RAG检索系统导入失败: {e}")
    RAG_SYSTEM_AVAILABLE = False


class ResumeJobRecommendAPIView(View):
    """基于简历的RAG岗位推荐API视图"""
    
    # 支持的文件格式
    ALLOWED_EXTENSIONS = {'.pdf', '.doc', '.docx', '.txt'}
    
    # 最大文件大小（10MB）
    MAX_FILE_SIZE = 10 * 1024 * 1024

    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

    def post(self, request):
        """
        处理简历文件上传并推荐岗位
        
        请求格式：
        - Content-Type: multipart/form-data
        - 文件字段名: 'resume_file'
        - 可选参数: 'top_n' (推荐岗位数量，默认10)
        
        返回格式：
        {
            "success": true/false,
            "message": "操作信息",
            "data": {
                "resume_info": {
                    "file_name": "文件名",
                    "skills": [...],
                    "experience_years": int,
                    "education": str,
                    "location": str
                },
                "job_recommendations": [
                    {
                        "job_id": int,
                        "title": str,
                        "company": str,
                        "location": str,
                        "salary": str,
                        "description": str,
                        "match_score": float,
                        "match_reason": str,
                        "source": "ES/Milvus/Mixed"
                    }
                ],
                "recommendation_summary": {
                    "total_recommendations": int,
                    "avg_match_score": float,
                    "top_skills_matched": [...],
                    "search_methods_used": [...]
                }
            },
            "error": "错误信息（如有）"
        }
        """
        try:
            # 检查是否有文件上传
            if 'resume_file' not in request.FILES:
                return JsonResponse({
                    'success': False,
                    'message': '请选择要上传的简历文件',
                    'error': 'NO_FILE_UPLOADED'
                }, status=400)
            
            resume_file = request.FILES['resume_file']
            
            # 获取推荐数量参数
            top_n = int(request.POST.get('top_n', 10))
            if top_n > 50:  # 限制最大推荐数量
                top_n = 50
            
            # 验证文件
            validation_result = self._validate_file(resume_file)
            if not validation_result['valid']:
                return JsonResponse({
                    'success': False,
                    'message': validation_result['message'],
                    'error': validation_result['error_code']
                }, status=400)
            
            # 保存临时文件
            temp_file_path = self._save_temp_file(resume_file)
            
            try:
                # 执行RAG推荐流程
                recommendation_result = self._process_resume_rag(temp_file_path, resume_file.name, top_n)
                
                # 清理临时文件
                self._cleanup_temp_file(temp_file_path)
                
                if recommendation_result['success']:
                    return JsonResponse({
                        'success': True,
                        'message': '岗位推荐成功',
                        'data': recommendation_result['data']
                    })
                else:
                    return JsonResponse({
                        'success': False,
                        'message': recommendation_result['message'],
                        'error': recommendation_result['error_code']
                    }, status=500)
                    
            except Exception as e:
                # 确保清理临时文件
                self._cleanup_temp_file(temp_file_path)
                raise e
                
        except Exception as e:
            logger.error(f"简历上传处理异常: {str(e)}")
            return JsonResponse({
                'success': False,
                'message': '服务器内部错误，请稍后重试',
                'error': 'INTERNAL_SERVER_ERROR'
            }, status=500)

    def _validate_file(self, file) -> Dict[str, Any]:
        """
        验证上传的文件
        
        Args:
            file: Django UploadedFile对象
            
        Returns:
            Dict: 验证结果
        """
        # 检查文件名
        if not file.name:
            return {
                'valid': False,
                'message': '文件名无效',
                'error_code': 'INVALID_FILENAME'
            }
        
        # 检查文件扩展名
        file_extension = os.path.splitext(file.name.lower())[1]
        if file_extension not in self.ALLOWED_EXTENSIONS:
            return {
                'valid': False,
                'message': f'不支持的文件格式。支持的格式：{", ".join(self.ALLOWED_EXTENSIONS)}',
                'error_code': 'UNSUPPORTED_FORMAT'
            }
        
        # 检查文件大小
        if file.size > self.MAX_FILE_SIZE:
            return {
                'valid': False,
                'message': f'文件过大。最大支持{self.MAX_FILE_SIZE // (1024*1024)}MB',
                'error_code': 'FILE_TOO_LARGE'
            }
        
        # 检查文件是否为空
        if file.size == 0:
            return {
                'valid': False,
                'message': '文件为空',
                'error_code': 'EMPTY_FILE'
            }
        
        return {
            'valid': True,
            'message': '文件验证通过'
        }

    def _save_temp_file(self, file) -> str:
        """
        保存临时文件
        
        Args:
            file: Django UploadedFile对象
            
        Returns:
            str: 临时文件路径
        """
        # 获取文件扩展名
        file_extension = os.path.splitext(file.name.lower())[1]
        
        # 创建临时文件
        temp_file = tempfile.NamedTemporaryFile(
            delete=False, 
            suffix=file_extension,
            prefix='resume_upload_'
        )
        
        # 写入文件内容
        for chunk in file.chunks():
            temp_file.write(chunk)
        
        temp_file.close()
        
        return temp_file.name

    def _process_resume_rag(self, file_path: str, original_filename: str, top_n: int) -> Dict[str, Any]:
        """
        执行基于简历的RAG岗位推荐
        
        Args:
            file_path: 临时文件路径
            original_filename: 原始文件名
            top_n: 推荐岗位数量
            
        Returns:
            Dict: RAG推荐结果
        """
        try:
            print(f"🔍 RAG系统可用性: {RAG_SYSTEM_AVAILABLE}")
            print(f"📂 文件路径: {file_path}")
            print(f"📄 文件名: {original_filename}")
            print(f"🎯 推荐数量: {top_n}")
            
            if not RAG_SYSTEM_AVAILABLE:
                print("❌ RAG系统不可用，返回错误")
                return {
                    'success': False,
                    'message': 'RAG推荐系统不可用',
                    'error_code': 'RAG_UNAVAILABLE'
                }
            
            print(f"🚀 开始RAG推荐流程: {original_filename}")
            
            # 调用RAG系统的核心函数
            print("📞 调用 process_resume_and_recommend_jobs...")
            rag_result = process_resume_and_recommend_jobs(file_path, top_n=top_n)
            
            print(f"📊 RAG结果类型: {type(rag_result)}")
            print(f"📊 RAG结果长度: {len(rag_result) if rag_result and isinstance(rag_result, (dict, list)) else 'N/A'}")
            
            if rag_result:
                print(f"📋 RAG结果键: {list(rag_result.keys()) if isinstance(rag_result, dict) else 'Not a dict'}")
            
            if not rag_result:
                print("❌ RAG返回空结果")
                return {
                    'success': False,
                    'message': 'RAG推荐失败，返回结果为空',
                    'error_code': 'RAG_EMPTY_RESULT'
                }
            
            # 转换RAG结果为API响应格式
            print("🔄 转换RAG结果格式...")
            api_data = self._format_rag_result(rag_result, original_filename)
            
            print(f"✅ API数据生成完成，推荐岗位数: {len(api_data.get('job_recommendations', []))}")
            
            return {
                'success': True,
                'message': f'成功推荐{len(api_data["job_recommendations"])}个岗位',
                'data': api_data
            }
            
        except Exception as e:
            import traceback
            error_trace = traceback.format_exc()
            print(f"❌ RAG推荐异常: {str(e)}")
            print(f"🔍 异常堆栈: {error_trace}")
            logger.error(f"RAG推荐异常: {str(e)}\n{error_trace}")
            return {
                'success': False,
                'message': f'RAG推荐失败: {str(e)}',
                'error_code': 'RAG_ERROR'
            }

    def _format_rag_result(self, rag_result: Dict[str, Any], filename: str) -> Dict[str, Any]:
        """
        将RAG结果转换为API响应格式
        
        Args:
            rag_result: RAG系统的原始结果
            filename: 文件名
            
        Returns:
            Dict: 格式化的API响应数据
        """
        print(f"🔄 开始格式化RAG结果...")
        print(f"📊 RAG结果包含键: {list(rag_result.keys()) if isinstance(rag_result, dict) else 'Not a dict'}")
        
        # 提取简历信息
        resume_analysis = rag_result.get('resume_analysis', {})
        key_info = resume_analysis.get('key_info', {})
        
        print(f"📋 简历分析数据: {bool(resume_analysis)}")
        print(f"🔑 关键信息: {list(key_info.keys()) if key_info else 'Empty'}")
        
        # 提取推荐岗位
        recommendations = rag_result.get('recommendations', [])
        print(f"🎯 推荐岗位数量: {len(recommendations)}")
        
        # 格式化岗位推荐
        job_recommendations = []
        for i, rec in enumerate(recommendations):
            print(f"📄 处理推荐 {i+1}: {rec.get('job_info', {}).get('title', 'No title')}")
            
            # RAG系统返回的结构是 {'job_info': {...}, 'llm_analysis': {...}}
            job_info = rec.get('job_info', {})
            llm_analysis = rec.get('llm_analysis', {})
            
            # 获取来源信息
            sources = job_info.get('sources', ['Mixed'])
            source = sources[0] if sources else 'Mixed'
            if 'milvus' in sources and 'es' in sources:
                source = 'Mixed'
            elif 'milvus' in sources:
                source = 'Milvus'
            elif 'es' in sources:
                source = 'ES'
            
            # 格式化薪资
            salary = job_info.get('money', '')
            if salary and salary.isdigit():
                salary = f"{salary}元/月"
            
            # 构建岗位数据
            job_data = {
                'job_id': job_info.get('job_id', ''),
                'title': job_info.get('title', ''),
                'company': job_info.get('company_name', ''),
                'location': job_info.get('city_name', ''),
                'salary': salary,
                'description': job_info.get('description', '')[:300] + '...' if len(job_info.get('description', '')) > 300 else job_info.get('description', ''),
                'match_score': round(job_info.get('final_score', 0.0), 3),
                'match_reason': llm_analysis.get('recommendation_reason', '基于技能和经验匹配推荐'),
                'source': source
            }
            job_recommendations.append(job_data)
            print(f"✅ 岗位 {i+1} 格式化完成: {job_data['title']} @ {job_data['company']}")
        
        # 生成推荐摘要  
        summary = rag_result.get('summary', {})
        search_results = rag_result.get('search_results', {})
        
        print(f"📊 生成摘要信息...")
        print(f"📈 摘要数据: {bool(summary)}")
        print(f"🔍 搜索结果: {bool(search_results)}")
        
        # 构建简历信息
        skills_info = key_info.get('skills', {})
        all_skills = skills_info.get('all_skills', [])
        
        # 构建最终响应
        api_data = {
            'resume_info': {
                'file_name': filename,
                'skills': all_skills,
                'experience_years': key_info.get('experience_years', 0),
                'education': key_info.get('education', ''),
                'location': key_info.get('preferred_location', ''),
                'parsing_time': rag_result.get('processing_time', {}).get('total_time', 0)
            },
            'job_recommendations': job_recommendations,
            'recommendation_summary': {
                'total_recommendations': len(job_recommendations),
                'avg_match_score': round(sum(job['match_score'] for job in job_recommendations) / len(job_recommendations) if job_recommendations else 0, 3),
                'top_skills_matched': all_skills[:5],  # 前5个技能
                'search_methods_used': summary.get('search_methods_used', ['RAG混合检索']),
                'es_results_count': search_results.get('es_count', 0),
                'milvus_results_count': search_results.get('milvus_count', 0)
            }
        }
        
        print(f"✅ API数据格式化完成:")
        print(f"   📄 简历技能: {len(all_skills)} 项")
        print(f"   🎯 推荐岗位: {len(job_recommendations)} 个")
        print(f"   📈 平均匹配度: {api_data['recommendation_summary']['avg_match_score']}")
        
        return api_data

    def _cleanup_temp_file(self, file_path: str):
        """
        清理临时文件
        
        Args:
            file_path: 临时文件路径
        """
        try:
            if os.path.exists(file_path):
                os.unlink(file_path)
                logger.info(f"临时文件已清理: {file_path}")
        except Exception as e:
            logger.warning(f"清理临时文件失败: {file_path}, 错误: {str(e)}")

    def get(self, request):
        """
        GET请求返回API使用说明
        """
        return JsonResponse({
            'api_name': '基于简历的RAG岗位推荐API',
            'version': '2.0',
            'description': '接收前端上传的简历文件，通过RAG流程检索匹配岗位并返回推荐结果',
            'methods': ['POST'],
            'supported_formats': list(self.ALLOWED_EXTENSIONS),
            'max_file_size': f'{self.MAX_FILE_SIZE // (1024*1024)}MB',
            'rag_features': [
                'ES关键词检索',
                'Milvus语义检索', 
                'LLM智能分析',
                '混合结果融合',
                '推荐理由生成'
            ],
            'usage': {
                'url': '/api/resume/recommend/',
                'method': 'POST',
                'content_type': 'multipart/form-data',
                'form_fields': {
                    'resume_file': '简历文件 (必需)',
                    'top_n': '推荐岗位数量 (可选，默认10，最大50)'
                },
                'example_curl': 'curl -X POST -F "resume_file=@/path/to/resume.pdf" -F "top_n=15" http://localhost:8000/api/resume/recommend/'
            },
            'response_format': {
                'success': 'boolean',
                'message': 'string',
                'data': {
                    'resume_info': {
                        'file_name': 'string',
                        'skills': 'array',
                        'experience_years': 'integer',
                        'education': 'string',
                        'location': 'string'
                    },
                    'job_recommendations': 'array of job objects',
                    'recommendation_summary': {
                        'total_recommendations': 'integer',
                        'avg_match_score': 'float',
                        'search_methods_used': 'array'
                    }
                },
                'error': 'string (if error)'
            }
        })


# 函数式视图（如果需要）
@csrf_exempt
@require_http_methods(["POST"])
def upload_resume_file(request):
    """
    函数式视图版本的简历文件上传处理
    """
    view = ResumeUploadAPIView()
    return view.post(request)


# 简化版API（只返回文本内容）
@csrf_exempt
@require_http_methods(["POST"])
def upload_resume_simple(request):
    """
    简化版简历上传API，只返回解析后的文本内容
    
    返回格式：
    {
        "success": true/false,
        "content": "解析后的文本内容",
        "message": "操作信息"
    }
    """
    try:
        if 'resume_file' not in request.FILES:
            return JsonResponse({
                'success': False,
                'message': '请选择要上传的简历文件'
            }, status=400)
        
        resume_file = request.FILES['resume_file']
        
        # 基本验证
        if resume_file.size == 0:
            return JsonResponse({
                'success': False,
                'message': '文件为空'
            }, status=400)
        
        # 检查文件格式
        file_extension = os.path.splitext(resume_file.name.lower())[1]
        if file_extension not in {'.pdf', '.doc', '.docx', '.txt'}:
            return JsonResponse({
                'success': False,
                'message': '不支持的文件格式'
            }, status=400)
        
        # 保存临时文件
        temp_file = tempfile.NamedTemporaryFile(
            delete=False, 
            suffix=file_extension,
            prefix='resume_simple_'
        )
        
        for chunk in resume_file.chunks():
            temp_file.write(chunk)
        temp_file.close()
        
        try:
            # 解析内容
            if RESUME_PARSER_AVAILABLE:
                content = parse_resume_content(temp_file.name)
            else:
                # 如果解析模块不可用，读取原始内容
                if file_extension == '.txt':
                    with open(temp_file.name, 'r', encoding='utf-8') as f:
                        content = f.read()
                else:
                    content = "解析模块不可用，无法处理此文件格式"
            
            # 清理临时文件
            os.unlink(temp_file.name)
            
            return JsonResponse({
                'success': True,
                'content': content,
                'message': '文件解析成功',
                'file_info': {
                    'name': resume_file.name,
                    'size': resume_file.size,
                    'content_length': len(content)
                }
            })
            
        except Exception as e:
            # 确保清理临时文件
            if os.path.exists(temp_file.name):
                os.unlink(temp_file.name)
            
            return JsonResponse({
                'success': False,
                'message': f'文件解析失败: {str(e)}'
            }, status=500)
            
    except Exception as e:
        logger.error(f"简历上传处理异常: {str(e)}")
        return JsonResponse({
            'success': False,
            'message': '服务器内部错误'
        }, status=500)
